﻿﻿using System;
﻿using System.Text;
using System.Net.Mail;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace DotNet.Helper
{
    /// <summary>
    /// 邮件帮助类
    /// </summary>
    public class MailHelper
    {
        #region 发送邮件(同步)
        /// <summary>
        /// 发送邮件(同步)
        /// </summary>
        /// <param name="model">邮件实体</param>
        /// <returns></returns>
        public static MailResult Send(MailModel model)
        {
            MailMessage message = new MailMessage();
            SmtpClient client = new SmtpClient();
            MailResult result = null;

            try
            {
                SetConfig(model, ref message, ref client);

                //发送
                client.Send(message);

                result = new MailResult();
            }
            catch (Exception ex)
            {
                result = new MailResult(false, ex);
            }
            finally
            {
                if (message != null)
                    message.Dispose();
                if (client != null)
                    client.Dispose();
            }
            return result;
        }
        #endregion

        #region 发送邮件(异步)
        /// <summary>
        /// 发送邮件(异步)
        /// </summary>
        /// <param name="model">邮件实体</param>
        /// <param name="handler">完成事件</param>
        /// <param name="obj">传递给完成事件的实体</param>
        public static MailResult SendAsync(MailModel model, SendCompletedEventHandler handler, object obj = null)
        {
            MailMessage message = new MailMessage();
            SmtpClient client = new SmtpClient();
            MailResult result = null;

            try
            {
                SetConfig(model, ref message, ref client);

                if (handler != null)
                {
                    client.SendCompleted += handler;
                }
                
                //发送
                //注：message和client的Dispose必须放到SendCompleted事件中执行，不然会导致发信被取消
                client.SendAsync(message, new MailAsyncResult(message, client, obj));

                result = new MailResult();
            }
            catch (Exception ex)
            {
                result = new MailResult(false, ex);
            }
            return result;
        }
        #endregion

        #region 发送邮件(异步)Task
        /// <summary>
        /// 发送邮件(异步)
        /// 需要framework 4.5支持
        /// </summary>
        /// <param name="model">邮件实体</param>
        /// <returns></returns>
        public static async Task<MailResult> SendMailAsync(MailModel model)
        {
            MailMessage message = new MailMessage();
            SmtpClient client = new SmtpClient();
            MailResult result = null;

            try
            {
                SetConfig(model, ref message, ref client);

                //发送
                await client.SendMailAsync(message);


                result = new MailResult(true, null);
            }
            catch (Exception ex)
            {
                result = new MailResult(false, ex);
            }
            finally
            {
                if (message != null)
                    message.Dispose();
                if (client != null)
                    client.Dispose();
            }
            return result;
        }
        #endregion

        #region 设置
        /// <summary>
        /// 设置
        /// </summary>
        /// <param name="model">邮件实体</param>
        /// <param name="message"></param>
        /// <param name="client"></param>
        private static void SetConfig(MailModel model, ref MailMessage message, ref SmtpClient client)
        {
            //设置邮件标题
            message.Subject = model.Subject;
            //设置邮件标题使用的编码
            message.SubjectEncoding = model.Encode;
            //设置邮件的发件人
            var address = new MailAddress(model.From);
            message.From = address;
            //设置邮件的收件人
            foreach (string email in model.To)
            {
                if (!string.IsNullOrEmpty(email.Trim()))
                {
                    message.To.Add(email.Trim());
                }
            }
            //设置邮件的抄送人
            foreach (string email in model.CC)
            {
                if (!string.IsNullOrEmpty(email.Trim()))
                {
                    message.CC.Add(email.Trim());
                }
            }
            //设置邮件的密送人
            foreach (string email in model.Bcc)
            {
                if (!string.IsNullOrEmpty(email.Trim()))
                {
                    message.Bcc.Add(email.Trim());
                }
            }
            //设置邮件的内容
            message.Body = model.Body;
            //设置邮件的格式
            message.BodyEncoding = model.Encode;
            //设置邮件正文是否为html格式
            message.IsBodyHtml = model.IsBodyHtml;
            //设置邮件的发送级别
            message.Priority = model.Priority;
            //设置发送通知
            message.DeliveryNotificationOptions = model.Options;


            //设置用于 SMTP 事务的主机的名称，填IP地址也可以
            client.Host = model.SMTPHost;
            //设置用于 SMTP 事务的端口，默认的是 25
            client.Port = model.SMTPPort;
            /*
             *有些 SMTP 服务器要求在代表客户端发送电子邮件前验证客户端的身份。 当此 SmtpClient 对象应该使用当前登录用户的默认凭
             *据进行身份验证（如果服务器要求）时，请将此属性设置为 true。 对于客户端应用程序，这是在大多数情况下都需要的行为。 
             * 
             * 如果 UseDefaultCredentials 属性设置为 true, 则连接到服务器时会将 Credentials 属性中设置的值用作凭据。 
             * 如果 UseDefaultCredentials 属性设置为 false 并且尚未设置 Credentials 属性，则将邮件以匿名方式发送到服务器。 
             */
            client.UseDefaultCredentials = false;
            //设置验证发信人身份的凭据
            client.Credentials = new System.Net.NetworkCredential(address.User, model.Pwd);
            //指定如何发送邮件
            client.DeliveryMethod = SmtpDeliveryMethod.Network;
            //ssl安全验证,某些邮箱需要SSL才能发送,如gmail
            client.EnableSsl = model.EnableSsl;
        }
        #endregion


    }

    #region 邮件实体
    /// <summary>
    /// 邮件实体
    /// </summary>
    public class MailModel
    {
        public MailModel()
        {
            Encode = Encoding.UTF8;
            To = new List<string>();
            CC = new List<string>();
            Bcc = new List<string>();
            IsBodyHtml = true;
            Priority = MailPriority.Normal;
            Options = DeliveryNotificationOptions.OnFailure;
            SMTPPort = 25;
            EnableSsl = false;
        }
        #region 邮件设置
        /// <summary>
        /// 邮件标题
        /// </summary>
        public string Subject { get; set; }
        /// <summary>
        /// 邮件内容
        /// </summary>
        public string Body { get; set; }
        /// <summary>
        /// 邮件编码，默认为UTF8
        /// </summary>
        public Encoding Encode { get; set; }
        /// <summary>
        /// 正文是否为html格式，默认是
        /// </summary>
        public bool IsBodyHtml { get; set; }
        /// <summary>
        /// 邮件优先级别，默认普通
        /// </summary>
        public MailPriority Priority { get; set; }
        /// <summary>
        /// 设置通知，默认失败通知
        /// </summary>
        public DeliveryNotificationOptions Options { get; set; } 
        #endregion

        #region 收发信人设置
        /// <summary>
        /// 发件人
        /// </summary>
        public string From { get; set; }
        /// <summary>
        /// 收件人
        /// </summary>
        public List<string> To { get; set; }
        /// <summary>
        /// 抄送人
        /// </summary>
        public List<string> CC { get; set; }
        /// <summary>
        /// 密送人
        /// </summary>
        public List<string> Bcc { get; set; } 
        #endregion

        #region SMTP设置
        /// <summary>
        /// SMTP主机地址
        /// </summary>
        public string SMTPHost { get; set; }
        /// <summary>
        /// SMTP主机端口，默认25
        /// </summary>
        public int SMTPPort { get; set; }
        /// <summary>
        /// 发信邮箱密码
        /// </summary>
        public string Pwd { get; set; }
        /// <summary>
        /// 是否启用SSL，默认不启用
        /// </summary>
        public bool EnableSsl { get; set; } 
        #endregion
    } 
    #endregion

    #region 邮件发送结果类
    /// <summary>
    /// 邮件发送结果类
    /// </summary>
    public class MailResult
    {
        public MailResult()
        {
            Flag = true;
        }

        public MailResult(bool flag, Exception ex)
        {
            Flag = flag;
            Exception = ex;
        }

        public bool Flag { get; set; }
        public Exception Exception { get; set; }
    }
    #endregion

    #region 异步结果类
    /// <summary>
    /// 异步结果类
    /// </summary>
    public class MailAsyncResult
    {
        public MailAsyncResult()
        {

        }
        public MailAsyncResult(MailMessage message, SmtpClient smtp, object data)
        {
            this.message = message;
            this.smtp = smtp;
            this.data = data;
        }

        public MailMessage message { get; set; }
        public SmtpClient smtp { get; set; }
        public object data { get; set; }
    }
    #endregion
}
